package com.ice.client.proto;

import com.ice.remoting.data.RemotingCommand;
import com.ice.remoting.utils.ModbusCrc16Utils;
import com.ice.remoting.utils.NetUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@ChannelHandler.Sharable
public class ProtobufMsgEncode extends MessageToByteEncoder<RemotingCommand> {

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, RemotingCommand msg, ByteBuf out)
            throws Exception {
        try {
            byte[] bytes = getBytes(msg);
            out.writeBytes(bytes);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    private byte[] getBytes(RemotingCommand remotingCommand) {
        ByteBuf byteBuf = Unpooled.buffer();
        byteBuf.writeBytes(ProtobufConstant.BEGIN_BYTES);
        byteBuf.writeBytes(NetUtil.short2byte((short) remotingCommand.getOpaque()));
        byteBuf.writeBytes(ProtobufConstant.TPC_IP);
        int length = remotingCommand.getBody().length + 2;
        byteBuf.writeBytes(NetUtil.short2byte((short) length));
        byteBuf.writeBytes(ProtobufConstant.UNIT_IDENTITY_TO_SERVER);
        byteBuf.writeByte(remotingCommand.getCommand());
        byteBuf.writeBytes(remotingCommand.getBody());
        byte[] checkCrc = calcCrc16(byteBuf, 7, length);
        byteBuf.writeBytes(checkCrc);
        byteBuf.writeBytes(ProtobufConstant.END_BYTES);
        return ByteBufUtil.getBytes(byteBuf);
    }


    /**
     * 校验CRC
     *
     * @Author wangwei
     * @Date 2024/1/30
     */
    public static byte[] calcCrc16(ByteBuf byteBuf, int offset, int byteLen) {
        int readIndex = byteBuf.readerIndex();
        byteBuf.resetReaderIndex();
        byteBuf.skipBytes(offset);
        byte[] bytes = new byte[byteLen];
        byteBuf.readBytes(bytes);
        byteBuf.readerIndex(readIndex);
        return ModbusCrc16Utils.getCrcByte(bytes);
    }
}
